package parseur;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import sparqlclient.SparqlInterface;

import beans.Paragraphe;
import beans.Query;
import beans.QueryAnswer;
import beans.QueryTerme;
import database.AppUtilInterface;

public class QueriesHandler extends DefaultHandler{
	//résultats de notre parsing
	private LinkedList<Query> lQueries;
	private Query query;
	private String text, narrative;
	//flags nous indiquant la position du parseur
	private boolean inQueries, inQuery, inText, inNarrative;
	//buffer nous permettant de récupérer les données 
	private StringBuffer buffer;
	//variables externes
	private AppUtilInterface dao;
	private SparqlInterface sparqlAns;
	private String queriesAnswerDirectory;
	private String queriesQrelDirectory;
	private boolean useSparql;

	// simple constructeur
	public QueriesHandler(AppUtilInterface dao, String queriesAnswerDirectory, String queriesQrelDirectory, boolean useSparql, SparqlInterface sparqlAns){
		super();
		
		this.dao = dao;
		this.queriesAnswerDirectory = queriesAnswerDirectory;
		this.queriesQrelDirectory = queriesQrelDirectory;
		this.useSparql = useSparql;
		this.sparqlAns = sparqlAns;
	}
	//détection d'ouverture de balise
	public void startElement(String uri, String localName,
			String qName, Attributes attributes) throws SAXException{
		if(qName.equals("queries")){
			inQueries = true;
			lQueries = new LinkedList<Query>();
		}else if(qName.equals("query")){
			inQuery = true;
			
			query = new Query();
			query.setId(attributes.getValue("id"));
		}else if(qName.equals("text")){
			inText = true;
			buffer = new StringBuffer();
		}else if(qName.equals("narrative")){
			inNarrative = true;
			buffer = new StringBuffer();
		}else {
			//erreur, on lève une exception
			throw new SAXException("Balise "+qName+" inconnue.");
		}
	}
	//détection fin de balise
	public void endElement(String uri, String localName, String qName)
			throws SAXException{
		if(qName.equals("queries")){
			inQueries = false;
		}else if(qName.equals("query")){
			inQuery = false;
			
			query.setTermes(text, useSparql, sparqlAns);
			query.setTexte(narrative);
			
			lQueries.add(query);
			query = null;
		}else if(qName.equals("text")){
			inText = false;
			
			// Enregistrement du texte court
			text = buffer.toString();
			buffer = null;
		}else if(qName.equals("narrative")){
			inNarrative = false;
			
			// Enregistrement du texte narratif
			narrative = buffer.toString();
			buffer = null;
		}else {
			//erreur, on lève une exception
			throw new SAXException("Balise "+qName+" inconnue.");
		}
	}
	//détection de caractères
	public void characters(char[] ch,int start, int length)
			throws SAXException{
		String lecture = new String(ch,start,length);
		if(buffer != null) buffer.append(lecture);       
	}
	//début du parsing
	public void startDocument() throws SAXException {
		System.out.println("Début du parsing du fichier de requête (" + new Date() + ")");
	}
	//fin du parsing
	public void endDocument() throws SAXException {
		System.out.println("Fin du parsing du fichier de requête");
		System.out.println("Calcul des paragraphes pertinents");
		
		//Tableau pour le calcul de la moyenne
		double[] tab_prf_moy = {0.0,0.0,0.0, 0.0,0.0,0.0, 0.0,0.0,0.0};
		
		for (Query q : lQueries) {
		//Query q = lQueries.get(0);{
			System.out.println("Début de la recherche des paragraphes pour la requête " + q.getId());
			System.out.println(q.getTermes());
			// hashmap contenant le vecteur associé à la requête par paragraphe concerné (contenant au moins un terme)
			QueryAnswer qanswer = new QueryAnswer(q.getTermes());
			
			try {
				// Calcul le vecteur par paragraphe et l'ajoute si besoin
				for (int idParagraphe=1; idParagraphe < dao.getNbLigneParagraphes(); idParagraphe++) {
					// Création du vecteur de base à remplir
					ArrayList<QueryTerme> qtermeListe = qanswer.duplicateQtermesListeRef();
					
					// Booléen pour savoir si le paragraphe contient au moins un terme
					boolean isConcerned = false;
					
					// Calcul le facteur tf.idf par terme pour le paragraphe concern�
					for (QueryTerme qterme : qtermeListe) {
						qterme.setTfIdf(dao.getTfIdf(idParagraphe, qterme.getTerme()));
						
						if (qterme.getTfIdf() != 0.0)
							isConcerned = true;
					}
					
					if (isConcerned) {
						//Rajoute 1 au poids des termes qui se suivent dans ce paragraphe
						addPoidsTermesFollowed(qtermeListe, idParagraphe);
						// Création du paragraphe avec le filepath et le xpath (clé de la hashmap qanswer)
						Paragraphe paragraphe = new Paragraphe();
						String[] paragraphePaths = dao.getParagraphePaths(idParagraphe);
						paragraphe.setFilepath(paragraphePaths[0]);
						paragraphe.setXpath(paragraphePaths[1]);
						
						// Ajout du paragraphe avec son vecteur associé
						qanswer.put(paragraphe, qtermeListe);
					}
					else
						qtermeListe.clear();
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			// Création du fichier de sortie
			System.out.println("Création du fichier de sortie");
			qanswer.createQanswerFile(queriesAnswerDirectory, q.getId(), queriesQrelDirectory);
			
			// Ajout pour calcul de la moyenne
			for (int i=0; i<9; i++) {
				try {
					tab_prf_moy[i] += qanswer.getPrf().get(i);
				}
				catch (IndexOutOfBoundsException ex) {}
			}
		}
		
		// Calcul et affichage de la moyenne des précisions, rappels et f à 5, 10 et 25
		int num = 0;
		for (int i=0; i<9; i++) {
			tab_prf_moy[i] /= lQueries.size();
			
			if (i%3 == 0) {
				num += 5;
				if (num == 15)
					num = 25;
				
				System.out.println("Précision à "+num+" = "+tab_prf_moy[i]);
			}
			else if (i%3 == 1) {
				System.out.println("Rappel à "+num+" = "+tab_prf_moy[i]);
			}
			else {
				System.out.println("F à "+num+" = "+tab_prf_moy[i]);
			}
		}
		
		System.out.println("Fin du calcul des paragraphes pertinents (" + new Date() + ")");
		System.out.println("Résultats dans le dossier " + queriesAnswerDirectory);
	}
	
	//Rajoute 1 au poids des termes qui se suivent dans une liste QueryTerme lié à un paragraphe
	private void addPoidsTermesFollowed(ArrayList<QueryTerme> qTermes, int idParagraphe) throws Exception{
		
		boolean isFoll = false;
		String terme1, terme2;
		
		Iterator<QueryTerme> it = qTermes.iterator();
		//index des elements dans la liste
		int i =0;
		//On parcourt la liste des termes jusqu'à l'avant dernier
		while(it.hasNext() && (i < qTermes.size()-1)){
			//On recupère les termes deux à deux
			terme1 = qTermes.get(i).getTerme();
			terme2 = qTermes.get(i+1).getTerme();
			//On verifie s'ils se suivent dans le paragraphe en question
			isFoll = dao.isFollowed(idParagraphe, terme1, terme2);
			//Si oui, on rajoute à leur poids respectif 1
			if (isFoll){
				qTermes.get(i).setPoids(qTermes.get(i).getPoids()+1);
				qTermes.get(i+1).setPoids(qTermes.get(i+1).getPoids()+1);
			}
			i++;
		}
		//On traite les deux derniers elements de la liste 
		if (dao.isFollowed(idParagraphe, qTermes.get(i-1).getTerme(), qTermes.get(i).getTerme())){
			qTermes.get(i).setPoids(qTermes.get(i).getPoids()+1);
			qTermes.get(i-1).setPoids(qTermes.get(i-1).getPoids()+1);
		}
	}
}
